package my.jypark.seminar;

import java.io.DataInputStream;
import java.io.IOException;
import java.util.LinkedList;

/**
 * Created with IntelliJ IDEA.
 * User: jypark
 * Date: 13. 10. 29
 * Time: 오후 12:10
 * To change this template use File | Settings | File Templates.
 */
public class CodeAttribute extends Attribute {
    private int maxStack;
    private int maxLocals;
    private int codeLen;
    private int exLen;
    private int attrCount;

    private static class Ex {
        short startPC;
        short endPC;
        short handlerPC;
        short catchType;
    }

    private Ex [] exlist;

    private static String [] opcode = {
            "nop",
            "aconst_null",
            "iconst_m1",
            "iconst_0",
            "iconst_1",
            "iconst_2",
            "iconst_3",
            "iconst_4",
            "iconst_5",
            "lconst_0",
            "lconst_1",
            "fconst_0",
            "fconst_1",
            "fconst_2",
            "dconst_0",
            "dconst_1",
            "bipush",
            "sipush",
            "ldc",
            "ldc_w",
            "ldc2_w",
            "iload",
            "lload",
            "fload",
            "dload",
            "aload",
            "iload_0",
            "iload_1",
            "iload_2",
            "iload_3",
            "lload_0",
            "lload_1",
            "lload_2",
            "lload_3",
            "fload_0",
            "fload_1",
            "fload_2",
            "fload_3",
            "dload_0",
            "dload_1",
            "dload_2",
            "dload_3",
            "aload_0",
            "aload_1",
            "aload_2",
            "aload_3",
            "iaload",
            "laload",
            "faload",
            "daload",
            "aaload",
            "baload",
            "caload",
            "saload",
            "istore",
            "lstore",
            "fstore",
            "dstore",
            "astore",
            "istore_0",
            "istore_1",
            "istore_2",
            "istore_3",
            "lstore_0",
            "lstore_1",
            "lstore_2",
            "lstore_3",
            "fstore_0",
            "fstore_1",
            "fstore_2",
            "fstore_3",
            "dstore_0",
            "dstore_1",
            "dstore_2",
            "dstore_3",
            "astore_0",
            "astore_1",
            "astore_2",
            "astore_3",
            "iastore",
            "lastore",
            "fastore",
            "dastore",
            "aastore",
            "bastore",
            "castore",
            "sastore",
            "pop",
            "pop2",
            "dup",
            "dup_x1",
            "dup_x2",
            "dup2",
            "dup2_x1",
            "dup2_x2",
            "swap",
            "iadd",
            "ladd",
            "fadd",
            "dadd",
            "isub",
            "lsub",
            "fsub",
            "dsub",
            "imul",
            "lmul",
            "fmul",
            "dmul",
            "idiv",
            "ldiv",
            "fdiv",
            "ddiv",
            "irem",
            "lrem",
            "frem",
            "drem",
            "ineg",
            "lneg",
            "fneg",
            "dneg",
            "ishl",
            "lshl",
            "ishr",
            "lshr",
            "iushr",
            "lushr",
            "iand",
            "land",
            "ior",
            "lor",
            "ixor",
            "lxor",
            "iinc",
            "i2l",
            "i2f",
            "i2d",
            "l2f",
            "l2f",
            "l2d",
            "f2i",
            "f2l",
            "f2d",
            "d2i",
            "d2l",
            "d2f",
            "i2b",
            "i2c",
            "i2s",
            "lcmp",
            "fcmpl",
            "fcmpg",
            "dcmpl",
            "dcmpg",
            "ifeq",
            "ifne",
            "iflt",
            "ifge",
            "ifgt",
            "ifle",
            "if_icmpeq",
            "if_acmpne",
            "if_icmplt",
            "if_icmpge",
            "if_icmpgt",
            "if_icmple",
            "if_acmpeq",
            "if_acmpne",
            "goto",
            "jsr",
            "ret",
            "tableswitch",
            "lookupswitch",
            "ireturn",
            "lreturn",
            "freturn",
            "dreturn",
            "areturn",
            "return",
            "getstatic",
            "putstatic",
            "getfield",
            "putfield",
            "invokevirtual",
            "invokespecial",
            "invokestatic",
            "invokeinterface",
            "unused",
            "new",
            "newarray",
            "anewarray",
            "arraylength",
            "athrow",
            "checkcast",
            "instanceof",
            "monitorenter",
            "monitorexit",
            "wide",
            "multianewarray",
            "ifnull",
            "ifnonnull",
            "goto_w",
            "jsr_w",
            "breakpoint",
    };

    public CodeAttribute(String name, DataInputStream ins) throws IOException {
        super(name, ins);
    }

    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer();

        sb.append("---- Code ----\n");
        sb.append("maxStack : ").append(maxStack).append('\n');
        sb.append("maxLocals : ").append(maxLocals).append('\n');

        sb.append("code length : ").append(codeLen).append('\n');

        sb.append('\n');
        int pc = 0;
        for (byte b:data) {
            sb.append(String.format("%d: %s (0x%X, %d)\n", pc++, opcode[0xFF & b], b, 0xFF & b));
        }
        sb.append('\n');

        sb.append("exception table length : " + exLen).append("\n");

        for(int i=0; i<exLen; i++) {
            sb.append("start PC : " + exlist[i].startPC).append("\n");
            sb.append("end PC : " + exlist[i].endPC).append("\n");
            sb.append("handler PC : " + exlist[i].handlerPC).append("\n");
            sb.append("catch type : " + exlist[i].catchType).append("\n");
        }

        sb.append("attribute count : " + attrCount).append("\n");

        for (Attribute attr:attrList) {
            sb.append("*****").append('\n');
            sb.append("attribute name : "+attr.getName()).append("\n");
            sb.append("attribute length : "+attr.getLen()).append("\n");

            sb.append(attr.toString());
        }

        sb.append("------------\n");

        return sb.toString();
    }

    @Override
    protected void readData(DataInputStream ins, int len) throws IOException {
        maxStack = ins.readShort();
        maxLocals = ins.readShort();
        codeLen = ins.readInt();

        data = new byte[codeLen];
        ins.read(data, 0, codeLen);

        exLen = ins.readShort();
        exlist = new Ex [exLen];

        for(int i=0; i<exLen; i++) {
            Ex ex = new Ex();

            ex.startPC = ins.readShort();
            ex.endPC = ins.readShort();
            ex.handlerPC = ins.readShort();
            ex.catchType = ins.readShort();

            exlist[i] = ex;
        }

        attrCount = ins.readShort();

        if (attrList == null)
            attrList = new LinkedList<Attribute>();

        for (int i=0; i<attrCount; i++) {
            Attribute attr = AttributeFactory.getReader(ins);
            attrList.add(attr);
        }
    }
}